//
//  DDFileReader.m
//  CommuteWarrior
//
//  Created by Rohit Mathews on 3/17/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "DDFileReader.h"

@interface NSData (DDAdditions)
-(NSRange) rangeOfData_dd:(NSData *)dataToFind;
@end

@implementation NSData(DDAdditions)

-(NSRange) rangeOfData_dd:(NSData *)dataToFind{
	const void *bytes = [self bytes];
	NSUInteger length = [self length];
	
	const void *searchBytes = [dataToFind bytes];
	NSUInteger searchLength = [dataToFind length];
	NSUInteger searchIndex = 0;
	
	NSRange foundRange = {NSNotFound, searchLength};
	for(NSUInteger index = 0;index < length; index++){
		if(((char *)bytes)[index] == ((char *)searchBytes)[searchIndex]){
			//the current character matches
			if(foundRange.location == NSNotFound){
				foundRange.location = index;
			}
			searchIndex++;
			if(searchIndex >= searchLength){
				return foundRange;
			}
		}
		else{
			searchIndex=0;
			foundRange.location=NSNotFound;
		}
	}
	return foundRange;
}
@end


@implementation DDFileReader

@synthesize lineDelimiter, chunkSize;

-(id) initWithFilePath:(NSString *)aPath{
	if(self = [super init]){
		fileHandle = [NSFileHandle fileHandleForReadingAtPath:aPath];
		if(fileHandle ==  nil){
			[self release];
			return nil;
		}
		
		lineDelimiter = [[NSString alloc] initWithString:@"\n"];
		[fileHandle retain];
		filePath = [aPath retain];
		currentOffset = 0ULL;
		chunkSize = 10;
		[fileHandle seekToEndOfFile];
		totalFileLength = [fileHandle offsetInFile];
	}
	return self;		
}

-(void) dealloc{
	[fileHandle closeFile];
	[fileHandle release]; fileHandle = nil;
	[filePath release]; filePath = nil;
	[lineDelimiter release]; lineDelimiter = nil;
	currentOffset = 0ULL;
	[super dealloc];
}

-(NSString *)readLine{
	if(currentOffset >= totalFileLength){return nil;}
	
	NSLog(@"Haven't reached end of file yet");
	NSData *newLineData = [lineDelimiter dataUsingEncoding:NSUTF8StringEncoding];
	[fileHandle seekToFileOffset:currentOffset];
	NSMutableData *currentData = [[NSMutableData alloc] init];
	BOOL shouldReadMore = YES;
	
	NSAutoreleasePool *readPool = [[NSAutoreleasePool alloc] init];	// For memory management. Releases all autorelease allocated memory chunks in range
	while(shouldReadMore){
		if(currentOffset>=totalFileLength){break;}
		NSData *chunk = [fileHandle readDataOfLength:chunkSize];
		NSRange newLineRange = [chunk rangeOfData_dd:newLineData];
		if(newLineRange.location != NSNotFound){
			//include the length so we can include the delimiter in the string
			chunk = [chunk subdataWithRange:NSMakeRange(0, newLineRange.location + [newLineData length])];
			shouldReadMore = NO;	// Because we have already found the \n character
		}
		[currentData appendData:chunk];
		currentOffset += [chunk length];	//We have read till the \n character
	}
	[readPool release];
	
	NSString *line = [[NSString alloc] initWithData:currentData encoding:NSUTF8StringEncoding];
	[currentData release];
	return [line autorelease];
}

-(NSString *) readTrimmedLine{
	return [[self readLine] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
	
@end
